const GLOBAL_CANVAS_CTX = document.createElement('canvas').getContext('2d')
function getOutputScale (ctx) {
    const devicePixelRatio = window.devicePixelRatio || 1
    const backingStoreRatio = ctx.webkitBackingStorePixelRatio ||
                            ctx.mozBackingStorePixelRatio ||
                            ctx.msBackingStorePixelRatio ||
                            ctx.oBackingStorePixelRatio ||
                            ctx.backingStorePixelRatio || 1
    const pixelRatio = devicePixelRatio / backingStoreRatio
    return {
        sx: pixelRatio,
        sy: pixelRatio,
        scaled: pixelRatio !== 1
    }
}

function approximateFraction (x) {
    // Fast paths for int numbers or their inversions.
    if (Math.floor(x) === x) {
        return [x, 1]
    }
    const xinv = 1 / x
    const limit = 8
    if (xinv > limit) {
        return [1, limit]
    } else if (Math.floor(xinv) === xinv) {
        return [1, xinv]
    }

    const x_ = x > 1 ? xinv : x
    // a/b and c/d are neighbours in Farey sequence.
    let a = 0; let b = 1; let c = 1; let d = 1
    // Limiting search to order 8.
    while (true) {
        // Generating next term in sequence (order of q).
        const p = a + c; let q = b + d
        if (q > limit) {
            break
        }
        if (x_ <= p / q) {
            c = p; d = q
        } else {
            a = p; b = q
        }
    }
    let result
    // Select closest of the neighbours to x.
    if (x_ - a / b < c / d - x_) {
        result = x_ === x ? [a, b] : [b, a]
    } else {
        result = x_ === x ? [c, d] : [d, c]
    }
    return result
}

function roundToDivide (x, div) {
    const r = x % div
    return r === 0 ? x : Math.round(x - r + div)
}

function getViewportSize (viewport) {
    const outputScale = getOutputScale(GLOBAL_CANVAS_CTX)

    const sfx = approximateFraction(outputScale.sx)
    const sfy = approximateFraction(outputScale.sy)
    return {
        width: roundToDivide(viewport.width * outputScale.sx, sfx[0]),
        height: roundToDivide(viewport.height * outputScale.sy, sfy[0]),
        styleWidth: roundToDivide(viewport.width, sfx[1]),
        styleHeight: roundToDivide(viewport.height, sfy[1])
    }
}

export { getViewportSize, getOutputScale }
